﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SCABaselineCS.Tests.LanguageFeatures
{
    public class MemberReferenceTests
    {
        // this just confirms that referenced an unreferenced members are identified correctly

        public class MyInstanceClass
        {
            // referenced within
            public static int StaticIntField;
            public static int StaticIntProperty { get; set; }
            public static void StaticMethod() { }

            // these will be referenced using fully qualified class name
            public static int qualified_StaticIntField;
            public static int qualified_StaticIntProperty { get; set; }
            public static void qualified_StaticMethod() { }

            // these should be the ONLY STATIC members that are identified as unreferenced
            public static int unreferenced_StaticIntField;
            public static int unreferenced_StaticIntProperty { get; set; } // should only be referenced once, not once for getter + once for setter
            public static void unreferenced_StaticMethod() { }

            // these should identify as being PARTIALLY unused (getter or setter)
            public static int unreferenced_StaticIntProperty_Getter { get; set; }
            public static int unreferenced_StaticIntProperty_Setter { get; set; }

            // referenced
            public int IntField;
            public int IntProperty { get; set; }
            public void Method() { }

            // these should be the only INSTANCE members that are identified as unreferenced
            public static int unreferenced_IntField;
            public static int unreferenced_IntProperty { get; set; } // should only be referenced once, not once for getter + once for setter
            public static void unreferenced_Method() { }


            public void References()
            {
                var s1 = StaticIntField;
                var s2 = StaticIntProperty; // getter
                StaticIntProperty = s2;     // setter
                StaticMethod();

                var s3 = MyInstanceClass.qualified_StaticIntField;
                var s4 = MyInstanceClass.qualified_StaticIntProperty; // getter
                MyInstanceClass.qualified_StaticIntProperty = s4;     // setter

                var s5 = unreferenced_StaticIntProperty_Setter;
                unreferenced_StaticIntProperty_Getter = s5;

                var i1 = this.IntField;
                var i2 = this.IntProperty; // getter
                this.IntProperty = f;     // setter
                this.Method();
            }


        }
        public static class MyStaticClass
        {
            public static int StaticIntField;
            public static int StaticIntProperty { get; set; }
            public static void StaticMethod() { }

            public static int qualified_StaticIntField;
            public static int qualified_StaticIntProperty { get; set; }
            public static void qualified_StaticMethod() { }

            // these should identify as being PARTIALLY unused (getter or setter)
            public static int unreferenced_IntProperty_Getter { get; set; }
            public static int unreferenced_IntProperty_Setter { get; set; }

            public static void References()
            {
                var a = StaticIntField;
                var b = StaticIntProperty; // getter
                StaticIntProperty = b;     // setter
                StaticMethod();

                var c = MyStaticClass.qualified_StaticIntField;
                var d = MyStaticClass.qualified_StaticIntProperty; // getter
                MyStaticClass.qualified_StaticIntProperty = d;     // setter

                var e = unreferenced_IntProperty_Setter;
                unreferenced_IntProperty_Getter = e;
            }
        }


        // todo : complex scenarios involving inheritance
        abstract public class MyBaseClass
        {
            public static int Referenced_Public_Static_Field;
            public static int Referenced_Public_Static_Property;
            public int Referenced_Public_Field;
            public int Referenced_Public_Property;

            protected static int Referenced_Protected_Static_Field;
            protected static int Referenced_Protected_Static_Property;
            protected int Referenced_Protected_Field;
            protected int Referenced_Protected_Property;

            abstract public int Referenced_Abstract_Public_Property { get; set; }
            abstract public void Referenced_Abstract_Public_Method();

            virtual public void Referenced_Virtual_Public_Method() { }
            virtual public void Referenced_Virtual_Overridden_Public_Method() { }
            virtual public void Referenced_Virtual_NotOverridden_Public_Method() { }

            virtual public void Unreferenced_Virtual_Public_Method() { }
            virtual public void Unreferenced_Virtual_Overridden_Public_Method() { }
            virtual public void Unreferenced_Virtual_NotOverridden_Public_Method() { }
        }

        public class MyBaseClassImplementation : MyBaseClass
        {
            public override int Referenced_Abstract_Public_Property { get { return 0; } set { } }
            public override void Referenced_Abstract_Public_Method() { }

            public override void Referenced_Virtual_Overridden_Public_Method() { }

            public override void Unreferenced_Virtual_Overridden_Public_Method() { }

            public void References()
            {

            }
        }



        public interface myInterface
        {
            void DoSomething();
        }
        public class myInterfaceImplicitImplementation : myInterface
        {
            public void DoSomething() { }
        }
        public class myInterfaceExplicitImplementation : myInterface
        {
            void myInterface.DoSomething() { }
        }
        
        private void UseMyInterface()
        {
            Action<myInterface> useInterface = o => { o.DoSomething(); };

            myInterface useImplicit = new myInterfaceImplicitImplementation();
            useInterface(useImplicit);

            myInterface useExplicit = new myInterfaceExplicitImplementation();
            useInterface(useExplicit);
        }


    } // class
} // namespace